package com.yjd.pub.system.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IpLocation {
	static String ipBinaryFilePath = "IpData";
	static File file = new File(ipBinaryFilePath);
	static ByteBuffer dataBuffer = ByteBuffer.allocate(new Long(file.length())
			.intValue());
	static FileInputStream fin;
	static ByteBuffer indexBuffer;
	static int offset;
	static int[] index = new int[256];
	static {
		try {

			file = new File(Thread.currentThread().getContextClassLoader()
					.getResource(ipBinaryFilePath).getPath());
			dataBuffer = ByteBuffer
					.allocate(new Long(file.length()).intValue());
			fin = new FileInputStream(file);
			int readBytesLength;
			byte[] chunk = new byte[4096];
			while (fin.available() > 0) {
				readBytesLength = fin.read(chunk);
				dataBuffer.put(chunk, 0, readBytesLength);
			}
			dataBuffer.position(0);
			int indexLength = dataBuffer.getInt();
			byte[] indexBytes = new byte[indexLength];
			dataBuffer.get(indexBytes, 0, indexLength - 4);
			indexBuffer = ByteBuffer.wrap(indexBytes);
			indexBuffer.order(ByteOrder.LITTLE_ENDIAN);
			offset = indexLength;

			int loop = 0;
			while (loop++ < 256) {
				index[loop - 1] = indexBuffer.getInt();
			}
			indexBuffer.order(ByteOrder.BIG_ENDIAN);
		} catch (IOException ioe) {
			//
		} finally {
			try {
				fin.close();
			} catch (IOException e) {
				//
			}
		}
	}

	public static IpLocation ip = new IpLocation();

	public static void main(String[] args) {

		for (int i = 0; i < 100; i++) {
			new Thread() {
				public void run() {
					try {
						System.out.println(java.util.Arrays.toString(ip
								.find("118.28.8.8")));
					} catch (UnsupportedEncodingException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}.start();
		}
	}

	/**
	 * 确保线程安全
	 * @throws UnsupportedEncodingException 
	 */
	public String[] find(String ip) throws UnsupportedEncodingException {
		String ips = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
				+ "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
				+ "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
				+ "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
		Pattern pattern = Pattern.compile(ips);
		Matcher matcher = pattern.matcher(ip);
		if (matcher.matches()) {
			int ip_prefix_value = new Integer(ip.substring(0, ip.indexOf(".")));
			long ip2long_value = ip2long(ip);
			int start = index[ip_prefix_value];
			int max_comp_len = offset - 1028;
			long tmpInt;
			long index_offset = -1;
			int index_length = -1;
			byte b = 0;
			for (start = start * 8 + 1024; start < max_comp_len; start += 8) {
				tmpInt = int2long(indexBuffer.getInt(start));
				if (tmpInt >= ip2long_value) {
					index_offset = bytesToLong(b, indexBuffer.get(start + 6),
							indexBuffer.get(start + 5),
							indexBuffer.get(start + 4));
					index_length = 0xFF & indexBuffer.get(start + 7);
					break;
				}
			}

			byte[] areaBytes;
			synchronized (dataBuffer) {
				dataBuffer.position(offset + (int) index_offset - 1024);
				areaBytes = new byte[index_length];
				dataBuffer.get(areaBytes, 0, index_length);
			}
			return new String(areaBytes,"UTF-8").split("\t");
		}else{
			return new String("IP地址异常").split("\t");
		}

	}

	public static long bytesToLong(byte a, byte b, byte c, byte d) {
		return int2long((((a & 0xff) << 24) | ((b & 0xff) << 16)
				| ((c & 0xff) << 8) | (d & 0xff)));
	}

	private static int str2Ip(String ip) {
		String[] ss = ip.split("\\.");
		int a, b, c, d;
		a = Integer.parseInt(ss[0]);
		b = Integer.parseInt(ss[1]);
		c = Integer.parseInt(ss[2]);
		d = Integer.parseInt(ss[3]);
		return (a << 24) | (b << 16) | (c << 8) | d;
	}

	private static long ip2long(String ip) {
		return int2long(str2Ip(ip));
	}

	private static long int2long(int i) {
		long l = i & 0x7fffffffL;
		if (i < 0) {
			l |= 0x080000000L;
		}
		return l;
	}
}